﻿using System.Windows;
using System.Windows.Media;
using System.Windows.Shapes;

namespace DynamicGeometry
{
    public class ArcBase : ShapeBase<Path>, ICircle
    {
        public override void UpdateVisual()
        {
            var p0 = Point(0);
            var p1 = Point(1);
            var p2 = Point(2);
            var startPoint = p1;
            var offset = p2.Minus(p0).Scale(Radius / p0.Distance(p2));
            var endPoint = p0.Plus(offset);

            var radius = ToPhysical(Radius);
            ArcShape.Size = new Size(radius, radius);
            Figure.StartPoint = ToPhysical(startPoint);
            ArcShape.Point = ToPhysical(endPoint);
            ArcShape.IsLargeArc = Math.OAngle(p1, p0, p2) > Math.PI;
        }

        public virtual double Radius
        {
            get
            {
                return Point(0).Distance(Point(1));
            }
        }

        public virtual Point Center
        {
            get
            {
                return Point(0);
            }
        }

        public PathFigure Figure { get; set; }
        public ArcSegment ArcShape { get; set; }

        public override IFigure HitTest(Point point)
        {
            if ((Radius - Center.Distance(point)).Abs() >= CursorTolerance)
            {
                return null;
            }
            var result = Math.GetAngle(Center, point);
            var a1 = Math.GetAngle(Center, Point(1));
            var a2 = Math.GetAngle(Center, Point(2));
            return Math.IsAngleBetweenAngles(result, a1, a2) ? this : null;
        }

        public virtual double GetNearestParameterFromPoint(Point point)
        {
            var result = Math.GetAngle(Center, point);
            var a1 = Math.GetAngle(Center, Point(1));
            var a2 = Math.GetAngle(Center, Point(2));
            if (a2 < a1)
            {
                if (result <= a2 || result >= a1)
                {
                    return result;
                }
                if (result > (a1 + a2) / 2)
                {
                    return a1;
                }
                else
                {
                    return a2;
                }
            }
            else if (result < a1 || result > a2)
            {
                return a1;
            }
            return result;
        }

        public virtual Point GetPointFromParameter(double parameter)
        {
            var center = Center;
            var radius = Radius;
            return new Point(
                center.X + radius * System.Math.Cos(parameter),
                center.Y + radius * System.Math.Sin(parameter));
        }

        public virtual Tuple<double, double> GetParameterDomain()
        {
            var a1 = Math.GetAngle(Center, Point(1));
            var a2 = Math.GetAngle(Center, Point(2));
            if (a2 < a1)
            {
                a2 += 2 * Math.PI;
            }
            return Tuple.Create(a1, a2);
        }

        protected override Path CreateShape()
        {
            ArcShape = new ArcSegment()
            {
                SweepDirection = SweepDirection.Counterclockwise,
                RotationAngle = 0
            };
            Figure = new PathFigure()
            {
                IsClosed = false,
                IsFilled = false,
                Segments = new PathSegmentCollection()
                {
                    ArcShape
                }
            };
            return new Path()
            {
                Data = new PathGeometry()
                {
                    Figures = new PathFigureCollection()
                    {
                        Figure
                    }
                },
                Stroke = new SolidColorBrush(Colors.Black),
                StrokeThickness = 1
            };
        }
    }
}
